module Debounce #(
    parameter CLK_MHZ = 50,         // 主时钟频率（单位：MHz）
    parameter DEBOUNCE_MS = 20      // 消抖时间（单位：ms）
)(
    input  logic clk,               // 系统时钟
    input  logic rst,               // 高电平有效复位
    input  logic button_in,         // 按键输入（低电平有效）
    output logic button_out         // 消抖输出（高电平单脉冲）
);

// 计算消抖所需时钟周期数
// 示例：50MHz时钟20ms => 20 * 50 * 1000 = 1,000,000周期
localparam DEBOUNCE_MAX = DEBOUNCE_MS * CLK_MHZ * 1000;

// 自动计算计数器位宽（防溢出）
// 例：1,000,000需要20位（2^19=524,288，2^20=1,048,576）
localparam COUNTER_WIDTH = $clog2(DEBOUNCE_MAX) + 1; 

// 两级同步器消除亚稳态
logic [1:0] sync_chain;
always_ff @(posedge clk or posedge rst) begin
    if (rst) sync_chain <= 2'b11;  // 复位时模拟按键未按下状态
    else     sync_chain <= {sync_chain[0], button_in};  // 移位寄存
end

// 状态机编码（二进制显式编码）
typedef enum logic [1:0] {
    IDLE            = 2'b00,  // 空闲状态
    PRESS_DEBOUNCE  = 2'b01,  // 按下消抖
    PRESSED         = 2'b10,  // 已按下状态
    RELEASE_DEBOUNCE= 2'b11   // 释放消抖
} state_t;

state_t state;                 // 当前状态
logic [COUNTER_WIDTH-1:0] debounce_cnt;  // 消抖计数器

always_ff @(posedge clk or posedge rst) begin
    if (rst) begin  // 复位初始化
        state <= IDLE;
        debounce_cnt <= 0;
        button_out <= 0;
    end else begin
        button_out <= 0;  // 默认无输出
        
        case (state)
            // IDLE：等待按键按下
            IDLE: begin
                if (!sync_chain[1]) begin  // 检测到下降沿
                    state <= PRESS_DEBOUNCE;
                    debounce_cnt <= 0;      // 启动消抖计数器
                end
            end
            
            // PRESS_DEBOUNCE：按下消抖阶段
            PRESS_DEBOUNCE: begin
                if (sync_chain[1]) begin   // 中途恢复高电平（抖动）
                    state <= IDLE;         // 返回空闲状态
                end else if (debounce_cnt == DEBOUNCE_MAX-1) begin
                    button_out <= 1;       // 消抖完成，输出脉冲
                    state <= PRESSED;      // 进入稳定按下状态
                    debounce_cnt <= 0;
                end else begin
                    debounce_cnt <= debounce_cnt + 1;  // 继续计数
                end
            end
            
            // PRESSED：稳定按下状态
            PRESSED: begin
                if (sync_chain[1]) begin   // 检测到上升沿
                    state <= RELEASE_DEBOUNCE;  // 进入释放消抖
                    debounce_cnt <= 0;
                end
            end
            
            // RELEASE_DEBOUNCE：释放消抖阶段
            RELEASE_DEBOUNCE: begin
                if (!sync_chain[1]) begin  // 中途再次按下（抖动）
                    state <= PRESS_DEBOUNCE;  // 重新进入按下消抖
                    debounce_cnt <= 0;
                end else if (debounce_cnt == DEBOUNCE_MAX-1) begin
                    state <= IDLE;         // 释放消抖完成
                end else begin
                    debounce_cnt <= debounce_cnt + 1;  // 继续计数
                end
            end
        endcase
    end
end

endmodule